﻿using System;
using System.Collections.Generic;
using System.Globalization;
using System.IO;
using System.Text;
using CarFileManager.Models;

namespace CarFileManager
{
    /// <summary>
    /// Describes the behaviour of a Car data storage implemented as a binary file.
    /// </summary>
    public sealed class BinaryCarFile : CarFileBase
    {
        /// <summary>
        /// Initialises a new instance of the BinaryCarFile.
        /// </summary>
        /// <param name="fileName">A full path to the binary file used as a Car data storage.</param>
        public BinaryCarFile(string fileName) : base(fileName)
        {
        }

        /// <summary>
        /// Reads the FileName specified file and fills the Cars collection.
        /// </summary>
        protected internal override void ReadFile()
        {
            using (var fileStream = new FileStream(FileName, FileMode.Open))
            {
                using (var reader = new BinaryReader(fileStream))
                {
                    var header = reader.ReadUInt16();
                    if (header != 0x2526)
                    {
                        // throw wrong file exception
                    }
                    var numberOfRecords = reader.ReadUInt32();
                    for (int i = 0; i < numberOfRecords; i++)
                    {
                        var dateChars = reader.ReadChars(8);
                        DateTime date;
                        if (!DateTime.TryParseExact(new string(dateChars), "ddMMyyyy", CultureInfo.InvariantCulture, DateTimeStyles.None, out date))
                        {
                            // throw wrong date
                        }
                        var brandNameLength = reader.ReadUInt16();
                        var brandNameBytes = reader.ReadBytes(brandNameLength);
                        var utf8 = new UTF8Encoding();
                        var brandName = utf8.GetString(brandNameBytes, 0, brandNameLength / 2);
                        var price = reader.ReadUInt32();

                        Cars.Add(new BinaryCar { BrandName = brandName, Date = date, Price = (int) price });
                    }
                }
            }
        }

        /// <summary>
        /// Saves the data from the Cars collection to the FileName specified file.
        /// </summary>
        protected internal override void SaveFile()
        {
            using (var fileStream = new FileStream(FileName, FileMode.Create))
            {
                using (var writer = new BinaryWriter(fileStream))
                {
                    // header - 2 bytes
                    writer.Write((ushort) 0x2526);
                    // number of records - 4 bytes
                    writer.Write((uint) Cars.Count);
                    foreach (var car in Cars)
                    {
                        // date - 8 bytes
                        var dateString = car.Date.ToString("ddMMyyyy", CultureInfo.InvariantCulture);
                        var dateChars = dateString.ToCharArray();
                        writer.Write(dateChars);
                        // brand name length - 2 bytes
                        writer.Write((ushort) (car.BrandName.Length * 2));
                        // brand name - brand name length * 2, unicode string
                        var utf8 = new UTF8Encoding();
                        var brandNameEncoded = utf8.GetBytes(car.BrandName);
                        var brandNameBytes = new byte[car.BrandName.Length * 2];
                        Array.Copy(brandNameEncoded, brandNameBytes, brandNameEncoded.Length);
                        writer.Write(brandNameBytes);
                        // price - 4 bytes
                        writer.Write((uint) car.Price);
                    }
                }
            }
        }
    }
}
